global tiles_asm

%define i [rbp - 8]
%define j r11
%define i_t [rbp - 16]
%define j_t r10
%define j_t_aux [rbp - 24]
%define tamx r12
%define tamy [rbp + 24]
%define offsetx [rbp + 32]
%define offsety [rbp + 40]
%define inicio_tile [rbp - 32]
%define src rdi
%define dst rsi
%define cols rdx
%define filas rcx
%define src_row_size r8
%define dst_row_size r9
%define dir_fila_tile r13
%define algun_borde 1

section .data

section .text
;void tiles_asm(unsigned char *src,
;              unsigned char *dst,
;              int cols,
;              int filas,
;              int src_row_size,
;              int dst_row_size );

tiles_asm:

;Parámetros
;rdi = src
;rsi = dst
;edx = cols
;ecx = filas
;r8d = src_row_size
;r9d = dst_row_size
;[rsp + 8] = tamx
;[rsp + 16] = tamy
;[rsp + 24] = offsetx
;[rsp + 32] = offsety

	push rbp
	mov rbp, rsp

;después de mov rsp, rbp, los siguientes parámetors quedan así en la pila
;[rbp + 16] = tamx
;[rbp + 24] = tamy
;[rbp + 32] = offsetx
;[rbp + 40] = offsety

	sub rsp, 60		;variables i, i_t
	push r12
	push r13
	push r14
	push rbx
	;Extensión con ceros de variables
	mov r14d, offsetx
	movsxd r14, r14d
	lea r14, [r14 + 2*r14]
	mov offsetx, r14
	mov r14d, offsety
	movsxd r14, r14d
	mov offsety, r14
	mov r14d, tamy
	movsxd r14, r14d
	mov tamy, r14
	movsxd tamx, [rbp + 16]
	lea tamx, [tamx + 2*tamx]
	movsxd cols, edx
	movsxd filas, ecx
	movsxd src_row_size, r8d
	movsxd dst_row_size, r9d

	mov qword i, 0
	mov j, 0
	mov qword i_t, 0
	mov j_t, 0
	mov r14, offsety
ubicar_src:
	cmp r14, 0
	je fin_ubicar_src
	lea src, [src + src_row_size]
	sub r14, 1
	jmp ubicar_src

fin_ubicar_src:
	add src, offsetx
	mov dir_fila_tile, src
	mov inicio_tile, src		;para recuperar la pos inicial del tile, si se supera tamy
	lea cols, [cols + cols*2]
col:
;	mov r14, rax
;	mov eax, r14d;duplicar el código
;	mov r15d, eax
;	mov r14w, r15w
;	mov r14, rax
;	mov eax, r14d
;	mov r15d, eax
;	mov r14w, r15w
;        mov r14, rax
;        mov eax, r14d
;        mov r15d, eax
;        mov r14w, r15w
;        mov r14, rax
;        mov eax, r14d
;        mov r15d, eax
;        mov r14w, r15w
	mov r14, [rbp - 32]
	movdqu xmm0, [src]
	movdqu [dst], xmm0
	cmp j_t, algun_borde		;algun_borde = 1
	je add_16_a_src_y_a_dst_j_t_1
	cmp j, algun_borde
	je add_16_a_src_y_a_dst_j_1
	add src, 15
	add dst, 15
	add j, 15
	add j_t, 15
	mov rax, tamx
	sub rax , j_t
	cmp rax, 16
	jl modificar_src		;chequea si está cerca de borde de tile
continuar:
	mov rbx, cols
	sub rbx, j			;rbx = cols - j
	cmp rbx, 16
	jg col				;chequea si está cerca de borde de dst
	je col
padding:
	cmp rbx, 0
	je cambiardefila
	mov j, 1
	mov j_t_aux, j_t
	sub qword j_t_aux, 16
	add j_t_aux, rbx
	cmp qword j_t_aux, 0
	jl copiar_memoria_partida	;si al retroceder dst para evitar leer padding, excedo el borde izquierdo de tile
					;o sea, si j_t_aux queda negativo, la subrutina se encarga de 
					;que copiar pixeles de dos filas del tile,
					;16 últimos de la fila anterior, y los 16 primeros de la fila actual.
					;Luego se obtienen en un registro multimedia los bytes que deben
					;ser copiados en dst, a partir de los 2 bloques de 16 mencionados anteriormente
	sub src, 16
	add src, rbx
	sub dst, 16
	add dst, rbx
	jmp col
cambiardefila:
	add qword i, 1
	cmp i, filas
	je fin_tiles
	;mov r14, i
	;mov i_t, r14
	add qword i_t, 1
	mov r14, tamy
	cmp i_t, r14
	je reiniciar_tile
	mov src, dir_fila_tile		;si i_t < tamy, bajo una fila del tile
	add src, src_row_size		;ubico a src en el principio de la siguiente fila del tile
volver_de_reiniciar_tile:
	mov dir_fila_tile, src		;guardo nuevo dir_fila_tile
	add dst, dst_row_size
	sub dst, cols			;ubico a dst al principio de la siguiente fila
	mov j, 0
	mov j_t, 0
	jmp col
fin_tiles:
	pop rbx
	pop r14
	pop r13
	pop r12
	add rsp, 60
	pop rbp
	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
modificar_src:
	cmp rax, 0
	je restart_fila_tile

	;else
	mov j_t, 1
	sub j, 16
	add j, rax
	sub src, 16
	add src, rax
	sub dst, 16
	add dst, rax
	jmp continuar

restart_fila_tile:
	mov src, dir_fila_tile
	mov j_t, 0
	jmp continuar

reiniciar_tile:
	mov src, inicio_tile
	mov qword i_t, 0
	jmp volver_de_reiniciar_tile
	
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
add_16_a_src_y_a_dst_j_t_1:
	add j, 16
	add dst, 16
	jmp restart_fila_tile

add_16_a_src_y_a_dst_j_1:
	add dst, 16
	jmp cambiardefila
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

copiar_memoria_partida:
	sub dst, 16
	add dst, rbx
	mov r14, dir_fila_tile
	add r14, tamx
	sub r14, 16
	movdqu xmm2, [r14]		;xmm2 = últimos 16 bytes de fila
	mov r14, dir_fila_tile
	movdqu xmm1, [r14]		;xmm1 = primeros 16 bytes de fila
	cmp rbx, 3
	jne comparar_con_6
	psrldq xmm2, 3
	pslldq xmm1, 13
	por xmm1, xmm2
	jmp copiar
comparar_con_6:
	cmp rbx, 6
	jne comparar_con_9
	psrldq xmm2, 6
	pslldq xmm1, 10
	por xmm1, xmm2
	jmp copiar
comparar_con_9:
	cmp rbx, 9
	jne comparar_con_12
	psrldq xmm2, 9
	pslldq xmm1, 7
	por xmm1, xmm2
	jmp copiar
comparar_con_12:
	cmp rbx, 12
	jne comparar_con_15
	psrldq xmm2, 12
	pslldq xmm1, 4
	por xmm1, xmm2
	jmp copiar
comparar_con_15:
	psrldq xmm2, 15
	pslldq xmm1, 1
	por xmm1, xmm2
	jmp copiar

copiar:
	movdqu [dst], xmm1
	add dst, 16
	jmp cambiardefila
